home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Browsers, Managers & Extensions / Mozilla Weave 0.2.7 / latest-weave.xpi / modules / crypto.js < prev    next >
Text File  |  2008-07-17  |  9KB  |  284 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Bookmarks Sync.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla.
  17.  * Portions created by the Initial Developer are Copyright (C) 2007
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Dan Mills <thunder@mozilla.com>
  22.  *  Justin Dolske <dolske@mozilla.com>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. const EXPORTED_SYMBOLS = ['Crypto'];
  39.  
  40. const Cc = Components.classes;
  41. const Ci = Components.interfaces;
  42. const Cr = Components.results;
  43. const Cu = Components.utils;
  44.  
  45. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  46. Cu.import("resource://weave/log4moz.js");
  47. Cu.import("resource://weave/constants.js");
  48. Cu.import("resource://weave/util.js");
  49. Cu.import("resource://weave/async.js");
  50.  
  51. Function.prototype.async = Async.sugar;
  52.  
  53. Utils.lazy(this, 'Crypto', CryptoSvc);
  54.  
  55. function CryptoSvc() {
  56.   this._init();
  57. }
  58. CryptoSvc.prototype = {
  59.   _logName: "Crypto",
  60.  
  61.   __os: null,
  62.   get _os() {
  63.     if (!this.__os)
  64.       this.__os = Cc["@mozilla.org/observer-service;1"]
  65.         .getService(Ci.nsIObserverService);
  66.     return this.__os;
  67.   },
  68.  
  69.   __crypto: null,
  70.   get _crypto() {
  71.     if (!this.__crypto)
  72.          this.__crypto = Cc["@labs.mozilla.com/Weave/Crypto;1"].
  73.                          createInstance(Ci.IWeaveCrypto);
  74.     return this.__crypto;
  75.   },
  76.  
  77.  
  78.   get defaultAlgorithm() {
  79.     return Utils.prefs.getCharPref("encryption");
  80.   },
  81.   set defaultAlgorithm(value) {
  82.     if (value != Utils.prefs.getCharPref("encryption"))
  83.       Utils.prefs.setCharPref("encryption", value);
  84.   },
  85.  
  86.   _init: function Crypto__init() {
  87.     this._log = Log4Moz.Service.getLogger("Service." + this._logName);
  88.     this._log.level =
  89.       Log4Moz.Level[Utils.prefs.getCharPref("log.logger.service.crypto")];
  90.     let branch = Cc["@mozilla.org/preferences-service;1"]
  91.       .getService(Ci.nsIPrefBranch2);
  92.     branch.addObserver("extensions.weave.encryption", this, false);
  93.   },
  94.  
  95.   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupports]),
  96.  
  97.   // nsIObserver
  98.  
  99.   observe: function Sync_observe(subject, topic, data) {
  100.     switch (topic) {
  101.     case "extensions.weave.encryption": {
  102.       if (Utils.pref.getCharPref("encryption") == data)
  103.         return;
  104.  
  105.       switch (data) {
  106.         case "none":
  107.           this._log.info("Encryption disabled");
  108.           break;
  109.  
  110.         default:
  111.           this._log.warn("Unknown encryption algorithm, resetting");
  112.           branch.clearUserPref("extensions.weave.encryption");
  113.           return; // otherwise we'll send the alg changed event twice
  114.       }
  115.       // FIXME: listen to this bad boy somewhere
  116.       this._os.notifyObservers(null, "weave:encryption:algorithm-changed", "");
  117.     } break;
  118.     default:
  119.       this._log.warn("Unknown encryption preference changed - ignoring");
  120.     }
  121.   },
  122.  
  123.   checkModule: function Crypto_checkModule() {
  124.     let ok = false;
  125.  
  126.     try {
  127.       let svc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
  128.         createInstance(Ci.IWeaveCrypto);
  129.       let iv = svc.generateRandomIV();
  130.       if (iv.length == 24)
  131.         ok = true;
  132.  
  133.     } catch (e) {}
  134.  
  135.     return ok;
  136.   },
  137.  
  138.   // Crypto
  139.  
  140.   encryptData: function Crypto_encryptData(data, identity) {
  141.     let self = yield;
  142.     let ret;
  143.  
  144.     this._log.trace("encrypt called. [id=" + identity.realm + "]");
  145.  
  146.     if ("none" == this.defaultAlgorithm) {
  147.       this._log.debug("NOT encrypting data");
  148.       ret = data;
  149.     } else {
  150.       let symkey = identity.bulkKey;
  151.       let iv     = identity.bulkIV;
  152.       ret = this._crypto.encrypt(data, symkey, iv);
  153.     }
  154.  
  155.     self.done(ret);
  156.   },
  157.  
  158.   decryptData: function Crypto_decryptData(data, identity) {
  159.     let self = yield;
  160.     let ret;
  161.  
  162.     this._log.trace("decrypt called. [id=" + identity.realm + "]");
  163.  
  164.     if ("none" == this.defaultAlgorithm) {
  165.       this._log.debug("NOT decrypting data");
  166.       ret = data;
  167.     } else {
  168.       let symkey = identity.bulkKey;
  169.       let iv     = identity.bulkIV;
  170.       ret = this._crypto.decrypt(data, symkey, iv);
  171.     }
  172.  
  173.     self.done(ret);
  174.   },
  175.  
  176.   /*
  177.    * randomKeyGen
  178.    *
  179.    * Generates a random symmetric key and IV, and puts them in the specified
  180.    * identity.
  181.    */
  182.   randomKeyGen: function Crypto_randomKeyGen(identity) {
  183.     let self = yield;
  184.  
  185.     this._log.trace("randomKeyGen called. [id=" + identity.realm + "]");
  186.  
  187.     let symkey = this._crypto.generateRandomKey();
  188.     let iv     = this._crypto.generateRandomIV();
  189.  
  190.     identity.bulkKey = symkey;
  191.     identity.bulkIV  = iv;
  192.   },
  193.  
  194.   /*
  195.    * RSAkeygen
  196.    *
  197.    * Generates a new RSA keypair, as well as the salt/IV used for protecting
  198.    * the private key, and puts them in the specified identity.
  199.    */
  200.   RSAkeygen: function Crypto_RSAkeygen(identity) {
  201.     let self = yield;
  202.  
  203.     this._log.trace("RSAkeygen called. [id=" + identity.realm + "]");
  204.     let privOut = {};
  205.     let pubOut  = {};
  206.  
  207.     // Generate a blob of random data for salting the passphrase used to
  208.     // encrypt the private key.
  209.     let salt = this._crypto.generateRandomBytes(32);
  210.     let iv   = this._crypto.generateRandomIV();
  211.  
  212.     this._crypto.generateKeypair(identity.password,
  213.                                  salt, iv,
  214.                                  pubOut, privOut);
  215.  
  216.     identity.keypairAlg     = "RSA";
  217.     identity.pubkey         = pubOut.value;
  218.     identity.privkey        = privOut.value;
  219.     identity.passphraseSalt = salt;
  220.     identity.privkeyWrapIV  = iv;
  221.   },
  222.  
  223.   wrapKey : function Crypto_wrapKey(data, identity) {
  224.     let self = yield;
  225.  
  226.     this._log.trace("wrapKey called. [id=" + identity.realm + "]");
  227.     let ret = this._crypto.wrapSymmetricKey(data, identity.pubkey);
  228.  
  229.     self.done(ret);
  230.   },
  231.  
  232.   unwrapKey: function Crypto_unwrapKey(data, identity) {
  233.     let self = yield;
  234.  
  235.     this._log.trace("upwrapKey called. [id=" + identity.realm + "]");
  236.     let ret = this._crypto.unwrapSymmetricKey(data,
  237.                                               identity.privkey,
  238.                                               identity.password,
  239.                                               identity.passphraseSalt,
  240.                                               identity.privkeyWrapIV);
  241.     self.done(ret);
  242.   },
  243.  
  244.   // This function tests to see if the passphrase which encrypts
  245.   // the private key for the given identity is valid.
  246.   isPassphraseValid: function Crypto_isPassphraseValid(identity) {
  247.     var self = yield;
  248.  
  249.     // We do this in a somewhat roundabout way; an alternative is
  250.     // to use a hard-coded symmetric key, but even that is still
  251.     // roundabout--ideally, the IWeaveCrypto interface should
  252.     // expose some sort of functionality to make this easier,
  253.     // or perhaps it should just offer this very function. -AV
  254.  
  255.     // Generate a temporary fake identity.
  256.     var idTemp = {realm: "Temporary passphrase validation"};
  257.  
  258.     // Generate a random symmetric key.
  259.     this.randomKeyGen.async(Crypto, self.cb, idTemp);
  260.     yield;
  261.  
  262.     // Encrypt the symmetric key with the user's public key.
  263.     this.wrapKey.async(Crypto, self.cb, idTemp.bulkKey, identity);
  264.     let wrappedKey = yield;
  265.     let unwrappedKey;
  266.  
  267.     // Decrypt the symmetric key with the user's private key.
  268.     try {
  269.       this.unwrapKey.async(Crypto, self.cb, wrappedKey, identity);
  270.       unwrappedKey = yield;
  271.     } catch (e) {
  272.       self.done(false);
  273.       return;
  274.     }
  275.  
  276.     // Ensure that the original symmetric key is identical to
  277.     // the decrypted version.
  278.     if (unwrappedKey != idTemp.bulkKey)
  279.       throw new Error("Unwrapped key is not identical to original key.");
  280.  
  281.     self.done(true);
  282.   }
  283. };
  284.